//
// Created by Gao Shihao on 2023/8/11.
//

#ifndef PLC2LLVM_BASICTYPE_H
#define PLC2LLVM_BASICTYPE_H

#include <plc2llvm/TypeSystem/Type.h>

#include <utility>

namespace plcst
{
    /*
     *
     * BasicType类型及其派生类
     *
     */
    class BasicType : public Type
    {
    public:
        using Type::Type;

        [[nodiscard]] TypeKind getTypeKind() const override = 0;

        [[nodiscard]] TypeCategory classify() const override;

        bool is_basic_type() override;

        [[nodiscard]] virtual int getNBits() const = 0;


        /// @brief 返回本类型转换为目标类型的可能性
        /// @param dest 目标类型指针
        virtual ConvertionSignal canConvertTo(std::shared_ptr<Type> dest) override{
            if(this->getTypeKind() == dest->getTypeKind()){ //类型相同
                return ConvertionSignal::IMPLICIT_CONVERSION;
            }

            auto largerTypeMsg = this->getLargerType(dest);

            switch(largerTypeMsg.signal){
                case 0:{ // no warnning
                    if(largerTypeMsg.t == dest){ // 目标类型更大，隐式转换
                        return ConvertionSignal::IMPLICIT_CONVERSION;
                    }else{ // 目标类型无法装下本类型，需要显式转换
                        return ConvertionSignal::EXPLICIT_CONVERSION;
                    }
                }
                case 1:{ // warnning
                    return ConvertionSignal::EXPLICIT_CONVERSION;
                }default:{
                    return ConvertionSignal::ERROR_CONVERSION;
                }
            }
        }

        /// @brief 二元操作符类型综合, this op another.
        /// @param op 二元操作符
        /// @param another 另一个操作数
        /// @return 综合得到的类型
        virtual TypeMsg typeSynthesisForBinaryOperator(ExpressionOperator op, std::shared_ptr<Type> another) = 0;

        /// @brief 一元操作符的类型综合，op this
        /// @param op 一元操作符
        /// @return 综合得到的类型
        virtual TypeMsg typeSynthesisForUnaryOperator(ExpressionOperator op) = 0;

        /// @brief 获得this类型和another更大的类型，比如INT和UINT会得到DINT
        /// @param another 另一个类型
        /// @return 一个更大的类型
        virtual TypeMsg getLargerType(std::shared_ptr<Type> another) = 0;

        virtual llvm::Value* castTo(std::shared_ptr<Type> destTy, llvm::Value* src, llvm::IRBuilder<>* builder) = 0;

        virtual std::shared_ptr<Type> clone() = 0;
    };
}

#endif // PLC2LLVM_BASICTYPE_H
